#ifndef SETTINGS_H
#define SETTINGS_H

#include "MML.h"

namespace Cvekas {

/// Wrapper for setting value with easy assignment and type casting
class SettingValue
{
public:
	SettingValue() {};
	SettingValue(const std::string& value) : value(value) {};
	SettingValue(const SettingValue& s) : value(s.value) {};

	template <typename T>
	SettingValue& operator=(const T& new_value)
	{
		value = boost::lexical_cast<std::string>(new_value);
		return *this;
	}

	template <typename T>
	operator T() const
	{
		return boost::lexical_cast<T>(value);
	}
private:
	std::string value;
};

/// Name-value pair container with easy serialization to MML
class SettingsGroup
{
public:
	/// Constructor
	SettingsGroup(const std::string& name, const std::string& filename = "");

	/// Copy constructor
	SettingsGroup(const SettingsGroup& group) 
		: name(group.name), filename(group.filename), settings(group.settings) {};

	/// Destructor
	virtual ~SettingsGroup() {};

	/// Reads settings from MMLNode. All existing settings are overwritten.
	/// \param mml MMLNode to parse from
	void deserialize(const MMLNode& mml);

	/// Puts all settings into MMLNode for easy saving
	MMLNode serialize() const;

	/// Returns reference to existing setting.
	/// \param name Name of setting
	virtual SettingValue& operator[](const std::string& name);

protected:
	std::string name;
	std::string filename;

	std::map<std::string, SettingValue> settings;

	friend class Settings;
};

/// Provides centralized access to all SettingGroups used by application
class Settings : public boost::noncopyable
{
public:
	/// Constructor
	Settings() {};

	/// Constructor. Loads groups from provided file
	/// \param filename Name of file containing one or more serialized SettingsGroups 
	Settings(const std::string& filename);

	/// Destructor
	virtual ~Settings() {};

	/// Reads groups from provided file. Already existing groups are overwritten!
	/// \param filename Name of file containing one or more serialized SettingsGroups
	void load(const std::string& filename);
	
	/// Saves group to its file. If file contains multiple groups those are saved as well.
	/// \param group_name Name of group to save
	void save(const std::string& group_name);

	/// Registers new group for managing. 
	/// \param name Name of new group. Must be unique, exception will be thrown if name is already used.
	/// \param group New group
	void insert(const std::string& name, const SettingsGroup& group);

	/// Returns reference to existing group. Throws exception if there is no such name.
	/// \param group_name Name of existing group
	SettingsGroup& operator[](const std::string& group_name);

private:
	std::map<std::string, SettingsGroup> groups;
};

typedef boost::shared_ptr<Settings> SettingsPtr;

} // namespace

#endif